﻿/*
 * Copyright (C) 2023 - 2024 lchfj.cn
 * 
 * This file is part of FastestHost.
 * 
 * FastestHost is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 * 
 * FastestHost is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along with FastestHost. If not, see <https://www.gnu.org/licenses/>.
 */

namespace Cn.Lchfj.FastestHost
{
    internal class Program
    {
        public static int CurrentProcessId { get; private set; }
        public static string CurrentPath { get; private set; } = string.Empty;
        public static RunSetting? Setting { get; private set; }

        private static void Main(string[] args)
        {
            ChangeThreadPoolMinThreads();
            CurrentProcessId = Environment.ProcessId;
            CurrentPath = Environment.ProcessPath!;

            if (!RunHelper.IsRunInUAC())
            {
                RunHelper.RunProcessOutline(CurrentPath, args);
                return;
            }




            Setting = RunHelper.Run(() => RunSetting.ReadFromArgs(args)) ?? RunHelper.Run(RunSetting.CreatNew);
            if (Setting is null)
                return;


            switch (Setting.Command)
            {
                case RunSetting.CommandTypeEnums.Install:
                    RunHelper.Run(Install);
                    RunHelper.ShowEndApplication();
                    break;
                case RunSetting.CommandTypeEnums.UnInstall:
                    RunHelper.Run(UnInstall);
                    RunHelper.ShowEndApplication();
                    break;
                case RunSetting.CommandTypeEnums.RunOneTime:
                    RunHelper.Run(RunWorkingAsync);
                    RunHelper.ShowEndApplication();
                    break;
                case RunSetting.CommandTypeEnums.AutoRun:
                    RunHelper.Run(AutoRunAsync);
                    break;
                case RunSetting.CommandTypeEnums.Update:
                    RunHelper.Run(Update.CheckUpdateManualAsync);
                    break;
                case RunSetting.CommandTypeEnums.UpdateFile:
                    RunHelper.Run(() => Update.UpdateFileAsync(Setting));
                    break;
                default:
                    break;
            }
        }

        private static async Task AutoRunAsync()
        {
            await Update.CheckUpdateAutoAsync();
            await RunWorkingAsync();
        }

        private static async Task Install()
        {
            ConsoleHelper.WriteLine("正在添加至计划任务中····");

            var argument = (Setting! with { Command = RunSetting.CommandTypeEnums.AutoRun }).GetArgument();

            var minitus = Random.Shared.Next(30);

            var cmd = new[] {
                "/Create",
                "/TN", "FastestHost",
                "/SC", "MINUTE",
                "/MO", "60",
                "/TR", $"'{CurrentPath}' {argument}",
                "/SD", "2020/01/01",
                "/ST", $"00:{minitus:00}",
                "/IT",
                "/RL", "HIGHEST",
                "/F"
            };

            var exe = "schtasks";

            await RunHelper.RunProcessInline(exe, cmd).WaitForExitAsync();
        }

        private static async Task UnInstall()
        {
            var cmd = new[] {
                "/Delete",
                "/TN", "FastestHost",
                "/F"
            };

            var exe = "schtasks";

            await LocalCheckHistory.DeleteHistoryAsync();
            await RunHelper.RunProcessInline(exe, cmd).WaitForExitAsync();
        }

        private static async Task RunWorkingAsync()
        {
            switch (Setting!.RunType)
            {
                case RunSetting.RunTypeEnums.Network:
                    await new RunNetwork(Setting).RunAsync();
                    break;
                case RunSetting.RunTypeEnums.Local:
                    await new RunLocal(Setting).RunAsync();
                    break;
                default:
                    break;
            }
        }

        private static void ChangeThreadPoolMinThreads()
        {
            ThreadPool.GetMinThreads(out var minWorker, out var minIO);
            ThreadPool.GetMaxThreads(out var maxWorker, out var maxIO);

            var newWorker = Math.Min(Math.Max(128, minWorker), maxWorker);
            var newIO = Math.Min(Math.Max(128, minIO), maxIO);

            ThreadPool.SetMinThreads(newWorker, newIO);
        }
    }
}
